package learn.up.java.thread.threads;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 *
 * @author NANUTO
 * @date 2017年12月10日 上午11:50:08
 */
public class ThreadPool1 {

	/**
	 * 创建一个可重用固定线程集合的线程池，以共享的无界队列方式来运行这些线程。
	 *  	有一个固定大小的池，如果当前需要执行的任务超过了池大小，那么多于的任务等待状态，
	 * 直到有空闲下来的线程执行任务，而当执行的任务小于池大小，空闲的线程也不会去销毁。
	 */
	ExecutorService pool = Executors.newFixedThreadPool(3);

	/**
	 * 创建一个可根据需要创建新线程的线程池，但是在以前构造的线程可用时将重用它们。
	 *  线程池的大小会根据执行的任务数动态分配
	 * 		 CachedThreadPool会创建一个缓存区，将初始化的线程缓存起来，如果线程有可用的，就使用之前
	 *  创建好的线程，如果没有可用的，就新创建线程，终止并且从缓存中移除已有60秒未被使用的线程。
	 */
	ExecutorService pool1 = Executors.newCachedThreadPool();

	/**
	 * 创建一个使用单个 worker 线程的 Executor，以无界队列方式来运行该线程。
	 * 创建单个线程的线程池，如果当前线程在执行任务时突然中断，则会创建一个新的线程替代它继续执行任务
	 * 这个线程会保证你的任务执行完成，这和我们直接创建线程不同，也和newFixedThreadPool(1)不同。
	 */
	ExecutorService pool2 = Executors.newSingleThreadExecutor();

	/**
	 * 创建一个可安排在给定延迟后运行命令或者定期地执行的线程池。 效果类似于Timer定时器
	 */
	ScheduledExecutorService pool3 = Executors.newScheduledThreadPool(5);

	/**
	 * 每种线程池都有不同的使用场景，下面看一下这四种线程池使用起来有什么不同。
	 */
	public static void main(String[] args) {
//		ExecutorService pool = Executors.newFixedThreadPool(3);
//		ExecutorService pool = Executors.newCachedThreadPool();
//		ExecutorService pool = Executors.newSingleThreadExecutor();
		ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
		schedule(pool);
	}

	public static void run(ExecutorService pool) {
		for (int i = 0; i < 5; i++) {
			int taskId = i;
			pool.execute(() -> {
				for (int j = 0; j < 5; j++) {
					try {
						Thread.sleep(30);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"  第" + taskId + "次任务的第" + j + "次执行");
				}
			});
		}
		System.out.println(Thread.activeCount());
		pool.shutdown();
	}
	
	private static void schedule(ScheduledExecutorService pool) {
		pool.schedule(() -> {
			 // 5秒后执行任务  
			System.out.println("boom!");
		}, 5, TimeUnit.SECONDS);
		
		// 5秒后执行任务，以后每2秒执行一次  
		pool.scheduleAtFixedRate(() -> {
			System.out.println("breaking");
		}, 5, 2, TimeUnit.SECONDS);
	}
}
